use std::cell::RefCell;
use std::rc::Rc;

use crate::instruction::instruction::Instruction;
use crate::native::native_method_register::NativeMethodRegister;
use crate::vm_thread::{VMFrame, VMThread};

pub struct invoke_native {
    pub sub_opcode: u8,
}

impl Instruction for invoke_native {
    fn read_operands(&mut self, frame: Rc<RefCell<VMFrame>>) {
        self.sub_opcode = frame.borrow_mut().read_u8();
    }

    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        let func = {
            let ro_frame = frame.borrow();
            let class_name = &ro_frame.current_vm_class.name;
            let method_name = &ro_frame.method.name;
            let class_method_descriptor_str = &ro_frame.method.descriptor.class_method_descriptor_str;

            let func_result = NativeMethodRegister::find_method(class_name, method_name, class_method_descriptor_str);
            if func_result.is_err() {
                panic!("{},{},{}", file!(), line!(), func_result.err().unwrap());
            }
            func_result.unwrap()
        };
        func(frame.clone(), thread);
    }

    fn to_string(&self) -> String {
        String::from("invoke_native")
    }
}